﻿using System;
using JetBrains.Annotations;

namespace FSM
{
    /// <summary>
    /// 有限状态机状态基类
    /// </summary>
    /// <typeparam name="T">有限状态机持有者类型</typeparam>
    public abstract class FsmState<T> where T : class
    {
        /// <summary>
        /// 有限状态机状态初始化时调用
        /// </summary>
        /// <param name="fsm"></param>
        protected internal virtual void OnInit(IFsm<T> fsm)
        {
        }
        
        /// <summary>
        /// 有限状态机状态进入时调用
        /// </summary>
        /// <param name="fsm"></param>
        protected internal virtual void OnEnter(IFsm<T> fsm)
        {
        }

        /// <summary>
        /// 有限状态机状态轮询时调用
        /// </summary>
        /// <param name="fsm"></param>
        /// <param name="elapseSeconds"></param>
        /// <param name="realElapseSeconds"></param>
        protected internal virtual void OnUpdate(IFsm<T> fsm, float elapseSeconds, float realElapseSeconds)
        {
        }

        /// <summary>
        /// 有限状态机状态离开时调用
        /// </summary>
        /// <param name="fsm"></param>
        /// <param name="isShutdown"></param>
        protected internal virtual void OnLeave(IFsm<T> fsm, bool isShutdown)
        {
        }

        /// <summary>
        /// 有限状态机状态销毁时调用
        /// </summary>
        /// <param name="fsm"></param>
        protected internal virtual void OnDestroy(IFsm<T> fsm)
        {
        }

        /// <summary>
        /// 切换当前有限状态机状态
        /// </summary>
        /// <param name="fsm"></param>
        /// <typeparam name="TState">新状态</typeparam>
        protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>
        {
            ((Fsm<T>)fsm ?? throw new Exception("FSM is invalid.")).ChangeState<TState>();
        }
        
        /// <summary>
        /// 切换当前有限状态机状态
        /// </summary>
        /// <param name="fsm"></param>
        /// <param name="stateType"></param>
        protected void ChangeState(IFsm<T> fsm, Type stateType)
        {
            Fsm<T> fsm1 = fsm as Fsm<T> ?? throw new Exception("FSM is invalid.");
            if (stateType == null)
                throw new Exception("State type is invalid.");
            if (!typeof(FsmState<T>).IsAssignableFrom(stateType))
                throw new Exception(string.Format("State type '{0}' is invalid.", stateType.FullName));
            fsm1.ChangeState(stateType);
        }
    }
}